home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 7 code / QuickTime / SimpleMovieOut / SimpleOutMovies.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-15  |  15.6 KB  |  537 lines  |  [TEXT/MPS ]

  1. /************************************
  2. *
  3.  
  4. * file: SimpleOutMovies.c
  5. *
  6. * Program: SimpleOutMovies
  7. * This program creates a movie by spooling in PICTs from a folder
  8. * and adding adding them one at a time to the movie. When all PICTs have
  9. * been processed a sound track is added if one is present.
  10. *
  11. *
  12. * This program uses the sequence compression commands
  13. * which make smaller movie files by only saving
  14. * the changes between frames
  15. *
  16. * In this file we have the basic creation of a movie
  17. * and the addition of video track.
  18. *
  19. * By Guillermo A. Ortiz 
  20. * April 1991
  21. *
  22. *
  23. * Heavily based on 
  24. * Rich Williams' Movie Construction FD
  25. * January, 1991
  26. *
  27. *    Apple Macintosh Developer Technical Support
  28. *
  29. *    Copyright © 1989-1991 Apple Computer, Inc.
  30. *    All rights reserved.
  31. *
  32. ************************************/
  33.  
  34. /* Revisions:
  35.  
  36. 08/06/91 ---     Changed interface for NewMovie.
  37.                 Changed interface for NewMovieTrack.
  38. 08/13/91 ---    Changed name GetCompressionSize in now GetMaxCompressionSize.
  39. 10/08/91 ---     Changed all else.
  40. */               
  41.  
  42. /************************************
  43. * Inclusions
  44. ************************************/
  45.  
  46. #define USEDUMP
  47.  
  48. #if !defined(USEDUMP)
  49.  
  50. #include <Types.h>
  51. #include <QuickDraw.h>
  52. #include <ToolUtils.h>
  53. #include <Events.h>
  54. #include <Controls.h>
  55. #include <Windows.h>
  56. #include <Dialogs.h>
  57. #include <Menus.h>
  58. #include <Desk.h>
  59. #include <SegLoad.h>
  60. #include <Files.h>
  61. #include <OSEvents.h>
  62. #include <Traps.h>
  63. #include <Fonts.h>
  64. #include <OSUtils.h>
  65. #include <Resources.h>
  66. #include <Memory.h>
  67. #include <Packages.h>
  68. #include <Lists.h>
  69. #include <Files.h>
  70. #include <Errors.h>
  71.  
  72. #pragma dump "SimpleOutMovies.dump"
  73.  
  74. #else
  75. #pragma load "SimpleOutMovies.dump"
  76. #endif
  77.  
  78. /* QuickTime Includes */
  79. #include "QDOffscreen.h"
  80. #include "Movies.h"
  81. #include "MoviesFormat.h"
  82. #include "ImageCompression.h"
  83.  
  84. // #define    __GETCODECINFO__ 
  85. /************************************
  86. * Limits and Konstants
  87. ************************************/
  88. #define kFrameX 120            /* Width & Height */
  89. #define kFrameY 100
  90. #define kPixelSize      32 
  91. #define kFrameCnt 1000        /* Number of frames to do */
  92. #define kTimeScale 10        /*  10 frames per second */
  93.  
  94. /************************************
  95. * Types and globals
  96. ************************************/
  97. /* Drawer receives these fields */
  98. typedef struct
  99.     {
  100.     long frameX,frameY;
  101.     long frameCnt;
  102.     long pixelSize;
  103.     } animationLimits;
  104.  
  105. /************************************
  106. * Prototypes
  107. ************************************/
  108. static void InitToolbox(void);
  109. static void MakeFrames(animationLimits *, WindowPtr);
  110. static void ConstructMovie(void);
  111. static FixParameters(animationLimits *, WindowPtr, Rect *);
  112.  
  113. void main(void);
  114.  
  115. extern void GetDirectory(void);
  116. extern OSErr OpenOneFile(PicHandle, short);
  117. extern OSErr AddSoundTrack( Movie, Handle);
  118.  
  119. extern Boolean            CurDirValid;
  120.  
  121. /************************************
  122. *
  123. * InitToolbox()
  124. *  Start up the tool (and the movie tools!)
  125. *
  126. ************************************/
  127. void InitToolbox()
  128. {
  129.     OSErr    theErr;
  130.  
  131.     InitGraf((Ptr) &qd.thePort);
  132.     InitFonts();
  133.     FlushEvents(0xffff,0);
  134.     InitWindows();
  135.     InitMenus();
  136.     InitDialogs(0);
  137.     TEInit();
  138.     InitCursor();
  139.     
  140.     theErr = EnterMovies();    /* Don't forget this. */
  141.     if (theErr) DebugStr("\pEnterMovies Failed"); /*   Real men don't use Alert Dialogs */
  142. }
  143.  
  144.  
  145. /************************************
  146. *
  147. * Construct Movie()
  148. *  Make a window and call MakeFrames
  149. *
  150. ************************************/
  151. void ConstructMovie()
  152. {
  153.     WindowPtr w;
  154.     Rect r;
  155.     animationLimits al;
  156.  
  157.     r.left = r.top = 0;
  158.     r.right = kFrameX;
  159.     r.bottom = kFrameY;
  160.  
  161.     OffsetRect(&r,100,100);
  162.     w = NewCWindow(0,&r,"\pFrames",true,0,(WindowPtr)-1,true,0);
  163.     SetPort(w);
  164.  
  165.     al.frameX = kFrameX;
  166.     al.frameY = kFrameY;
  167.     al.frameCnt = kFrameCnt;
  168.     al.pixelSize = kPixelSize;
  169.  
  170.     MakeFrames(&al, w);        /* write out lots of frames */
  171.     
  172.     CloseWindow(w);
  173. }
  174.  
  175. /* Once we know where to look for the frames we want to
  176.    change the parameters for the display window (this is cosmetic) and 
  177.    more important the limits for the animation based on the frame of the 
  178.    pictures. It is reasonable to assume that all frames will have the same dimentions.
  179. */
  180. FixParameters(al, w, r)
  181. animationLimits *al;
  182. WindowPtr w;
  183. Rect *r;
  184. {
  185. al->frameX = (r->right - r-> left) << 16; /* width and height are fixed values */
  186. al->frameY = (r->bottom - r->top) << 16;
  187. SizeWindow(w, (r->right - r-> left), (r->bottom - r->top), false);
  188. }
  189. /************************************
  190. *
  191. * MakeFrames(al)
  192. *  Here is where all the work happens
  193. *
  194. ************************************/
  195. void MakeFrames(al, w)
  196.  
  197. animationLimits *al;
  198. WindowPtr w;
  199.  
  200. {
  201.     short         theErr;                            /* latest error return */
  202.     short         resRefNum;                        /* for file i/o            */
  203.     long         i;                                /* the usual miscellaneous integer */
  204.     
  205.     /* Stuff for creating the file */
  206.     Point        dlgPos = {100,100};                /* Position the dialog box */
  207.     SFReply        sfr;                            /* StdFile reply */
  208.     FSSpec        mySpec;                            /* Data structure with filename, etc. */
  209.     Handle        mdrh;
  210.     short             resId;
  211.                 
  212.     /* movie time vars */
  213.     Movie        gMovie;
  214.     Track        gTrack;
  215.     Media        gMedia;
  216.  
  217.     /* Stuff for drawing our frames */
  218.     GWorldPtr     myGWorld,oldGWorld;
  219.     GDHandle     oldGDevice;
  220.     PixMap         *pm,**pmH;                        /* our offscreen pixmap                */
  221.     Rect         r;
  222.     PicHandle    pictureBuffer;
  223.     
  224.     /* Stuff for the compressor */
  225.     char         **compressedFrameBitsH;            /* Buffer for the compressed data    */
  226.     long maxCompressedFrameSize;                /* Max size of compressed frame    was UNSIGNED*/
  227.     long compressedFrameSize;                    /* Size of current compressed frame, was UNSIGNED*/
  228.  
  229.     CodecType    codecType;                        /* Type of codec to use JPEG etc    */
  230.     CompressorComponent codecID;                /* Which variation of codecType to use */
  231.     short        theDepth;                        /* Color depth to compress to        */
  232.     CodecQ         theQuality;                        /* Quality to compress to            */
  233.     ImageDescription    **imageDescriptorH;        /* Contains info about the sample    */
  234.     
  235.     CTabHandle ct = nil;  /* assume no color table is needed */
  236.     
  237.     /* For frame differencing, we also have these */
  238.     ImageSequence    seqID;                        /* Which sequence is being compressed */
  239.     unsigned char    similarity;                    /* Measure of how similar the frame is to the previous one */
  240.     long    keyFrameRate;                        /* # samples per key frame */    
  241.     CodecQ mQuality;                            /* Motion quality */
  242.     CodecInfo codecInf;
  243.     
  244.     /* Stuff for adding the sample */
  245.     TimeValue     sampTime;                        /* Time sample is added to media */
  246.     
  247.     /******************************
  248.     *
  249.     * Set values for Road Pizza compression
  250.     * You would let the user pick it with a dialog
  251.     *
  252.     *******************************/
  253.     codecID = anyCodec;
  254.     codecType = (CodecType) 'rpza';   /*   'rpza';  */
  255.     theDepth = 0;                                /* 16 is only color depth supported by 'rpza' */
  256.     theQuality = 0x200;                            /* Quality is 0x100 to 0x300 */
  257.  
  258.     mQuality = 0x200;
  259.     keyFrameRate = 10;                            /* 1 keyframe every 10 frames */
  260.  
  261.     
  262. /* this code shows how to make the call to get info on codec     */
  263. /* one important use of this call is to determine the formats    */
  264. /* supported by a codec. 'rpza' only supports 16                */
  265.  
  266.     theErr = GetCodecInfo(&codecInf, codecType, bestSpeedCodec);  
  267.       if (theErr )
  268.         DebugStr("/pCouldn't GetCodecInfo");
  269.  
  270.     /******************************
  271.     *
  272.     * First we make an empty movie
  273.     *
  274.     *******************************/
  275.  
  276.     /* Prompt the user for a file name and create it */
  277.     SFPutFile(dlgPos, "\pMovie file to create:","\pTempMovie",nil,&sfr);
  278.     if (!sfr.good)
  279.         return;                                    /* Return if cancel pressed */
  280.  
  281.     /* Now we ask the user to point to the folder where the pictures are,
  282.        then we allocate a handle to store the picts 
  283.     */
  284.     GetDirectory();
  285.     
  286.     if (! CurDirValid) { /* flag if the user selected a folder */
  287.       DebugStr("\pThe selection of folder failed");
  288.       return;
  289.     }
  290.     
  291.     /* In the sample we read in each PICT before calling drawpicture,
  292.        in a real application it would be better to use spooling so that bigger
  293.        PICTs can be used, the excuse is to make the sample simpler.
  294.        See IM V for details on the spooling trick.
  295.     */
  296.     pictureBuffer = (PicHandle)NewHandle(10);        /* Get a handle to store the picts */
  297.     if ( MemError() ) {
  298.       DebugStr("\pCould not allocate the buffer for picts");
  299.       return; /* user needs to increase the app's partition */
  300.     }
  301.     /* Before we start the movie making we want to make sure the dimentions of the
  302.        movie and window match the frames
  303.     */
  304.   for (i = 0; !(OpenOneFile(pictureBuffer, i+1)); i++) {    /* it is possible the selected folder has a non-PICT file */
  305.     if ( GetHandleSize((Handle)pictureBuffer) > 10 ) { /* in that case OpenOneFile set the handle size to ten */
  306.       FixParameters(al, w, &((*pictureBuffer)->picFrame));
  307.       break;        /* ok we have our data lets go ahead */
  308.     }
  309.   }
  310.  
  311.     /* OK we have the files alligned and now we can start doing the movie stuff */
  312.     ClearMoviesStickyError();                    /* Clear any old errors */
  313.  
  314.     /* system 6.0.x fans will use this to create a FSSSpec out of the of SFGetFile reply */
  315.     theErr = FSMakeFSSpec(sfr.vRefNum, 0, (unsigned char *) sfr.fName, &mySpec);
  316.     if (theErr == fnfErr) theErr = 0;
  317.     if (theErr) DebugStr("\pFSMakeFSSpec Failed");
  318.  
  319. /******* The interface changed so instead of 
  320.     theErr = CreateMovieFile(  &mySpec, 'TVOD',0,createMovieFileDeleteCurFile); we have: */
  321.     theErr = CreateMovieFile(  &mySpec, 'TVOD',0,createMovieFileDeleteCurFile, &resRefNum, nil);
  322.     if (theErr) DebugStr("\pCreateMovieFile Failed");
  323.  
  324. /******* The interface changed so instead of 
  325.     theErr = OpenMovieFile(  &mySpec, &resRefNum, fsRdWrPerm, &mdrh ); */
  326.     theErr = OpenMovieFile(  &mySpec, &resRefNum, fsRdWrPerm);
  327.     if (theErr) DebugStr("\pOpenMovieFile Failed");
  328.  
  329. /* create media to use as a reference */
  330.     theErr = NewAlias(nil, &mySpec, &(AliasHandle)mdrh);
  331.     if (theErr) DebugStr("\NewAlias Failed");
  332.     
  333.     /* Create the movie, track and media */
  334. /******* The interface changed so instead of 
  335.     gMovie = NewMovie(0,60);  
  336.        we now have:                        */
  337.     gMovie = NewMovie(0);            /* the flags ask for a inactive movie */
  338.     if (theErr = GetMoviesError()) DebugStr("\pNewMovie Failed");
  339.  
  340. /******* The interface changed so instead of 
  341.     gTrack = NewMovieTrack(gMovie,(TimeValue) 0,kTimeScale,al->frameX,al->frameY);
  342.        we now have:                        */
  343.     gTrack = NewMovieTrack(gMovie,al->frameX,al->frameY, kNoVolume);
  344.  
  345.     if (theErr = GetMoviesError()) DebugStr("\pNewMovieTrack Failed");
  346.  
  347. /******* changed interface ****/
  348.     gMedia = NewTrackMedia(gTrack, VIDEO_TYPE,kTimeScale, mdrh, 'alis');
  349.     if (theErr = GetMoviesError()) DebugStr("\pNewTrackMedia Failed");
  350.  
  351.     theErr = BeginMediaEdits( gMedia );        /* We do this since we are adding samples to the media */
  352.     if (theErr) DebugStr("\pBeginMediaEdits Failed");
  353.  
  354.     /******************************
  355.     *
  356.     * Now make a new GWorld to draw the frames to be compressed
  357.     *
  358.     *******************************/
  359.     GetGWorld(&oldGWorld,&oldGDevice);                    /* save the old port */
  360.  
  361.     r.left = r.top = 0;
  362.     r.right = al->frameX >> 16;                /* un_fix the values */
  363.     r.bottom = al->frameY >> 16;
  364.  
  365.     if (theErr = NewGWorld(&myGWorld, al->pixelSize,&r,nil,nil,0))
  366.         DebugStr("\pNewGWorld Failed");
  367.     pmH = myGWorld->portPixMap;                            /* GetGWorldPixMap doesn't always work */
  368.     LockPixels(pmH);
  369.     HLock((Handle) pmH);
  370.     pm = *pmH;                                            /* pm is pointer to pixel-map */
  371.  
  372.     /******************************
  373.     *
  374.     * Now make the buffers and stuff for the compressor
  375.     *
  376.     *******************************/
  377.  
  378.     imageDescriptorH = (ImageDescription **)NewHandle( 4 );    /* handle for image descriptor */
  379. /***** The name changed from GetCompressionSize to */
  380.     theErr = GetMaxCompressionSize(&pm,&r, theDepth,theQuality,
  381.                         codecType,codecID,&maxCompressedFrameSize);    /* How big a buffer do we need? */
  382.  
  383.     if (theErr) DebugStr("\pGetCompressionSize Failed");
  384.  
  385.     compressedFrameBitsH = NewHandle(maxCompressedFrameSize);    /* Make the buffer */
  386.     if (!compressedFrameBitsH) DebugStr("\pUnable to allocate compression buffer");
  387.  
  388.     HLock(compressedFrameBitsH);
  389.  
  390.     /******************************
  391.     *
  392.     * Tell the codec manager we are about to start a sequence 
  393.     *
  394.     *******************************/
  395.  
  396.     theErr = CompressSequenceBegin( &seqID,
  397.                     &pm, nil,
  398.                     &r, nil,
  399.                     theDepth, codecType, codecID,
  400.                     theQuality, 
  401.                     mQuality, keyFrameRate,
  402.                     ct /* no clut */, 
  403.                     codecFlagUpdatePrevious, 
  404.                     imageDescriptorH);
  405.  
  406.     if (theErr) DebugStr("\pCompressSequenceBegin Failed");
  407.  
  408.     /******************************
  409.     *
  410.     * Now put the movie together one frame at a time
  411.     *
  412.     * We call the proc to load in the PICT, if it succeeds we 
  413.     * call DrawPicture into our GWorld and add the image to the movie.
  414.     *
  415.     *******************************/
  416.  
  417.   for (i = 0; !(OpenOneFile(pictureBuffer, i+1)); i++)
  418.     {    /* it is possible the selected folder has a non-PICT file */
  419.       if ( GetHandleSize((Handle)pictureBuffer) > 10 ) { /* in that case OpenOneFile set the handle size to ten */
  420.         if(Button())                        /* A terrific user interface */
  421.         {
  422.             FlushEvents(0xffff,0);
  423.             ExitToShell();
  424.         }
  425.  
  426.         /******************************
  427.         *
  428.         * This is where we draw a single frame of the movie.
  429.         * We're only drawing black and white here, into our big
  430.         * 32-bit offscreen GWorld, because RAM is so cheap.
  431.         *
  432.         *******************************/
  433.  
  434.         SetGWorld(myGWorld,nil);
  435.         EraseRect(&r);                        /* erase the whole area to white */
  436.  
  437.         DrawPicture( pictureBuffer, &r);    /* replay the pict offscreen    */
  438.         
  439.         /******************************
  440.         *
  441.         * Go back to the old GWorld (the Window)
  442.         * and copybit the frame into it for something to watch
  443.         *
  444.         *******************************/
  445.  
  446.         SetGWorld(oldGWorld,oldGDevice);
  447.         CopyBits((BitMap  *) pm,(BitMap  *)(*(PixMapHandle)(qd.thePort->portBits.baseAddr)),&r,&r,0,0);
  448.  
  449.         /******************************
  450.         *
  451.         * Compress the Frame
  452.         *
  453.         *******************************/
  454.         compressedFrameSize = maxCompressedFrameSize;
  455.  
  456.         theErr = CompressSequenceFrame(seqID, /* the imageDescriptorH is filled here */
  457.                                         &pm,
  458.                                         &r,
  459.                                         codecFlagUpdatePrevious,
  460.                                         *compressedFrameBitsH,
  461.                                         &compressedFrameSize,
  462.                                         &similarity,
  463.                                         nil);
  464.         
  465.  
  466.         if (theErr) DebugStr("\pCompressSequenceFrame Failed");
  467.  
  468.         /******************************
  469.         *
  470.         * And add it to the media
  471.         *
  472.         *******************************/
  473.  
  474. /***** sampleNotSync changed to mediaSampleNotSync *****/
  475.         theErr = AddMediaSample(gMedia,compressedFrameBitsH,0L,compressedFrameSize,
  476.                                 (TimeValue)1,(SampleDescriptionHandle) imageDescriptorH,1L,
  477.                                 similarity?mediaSampleNotSync:0, &sampTime);
  478.  
  479.         if (theErr) DebugStr("\pAddMediaSample Failed");
  480.       }
  481.         /* And loop back for the next frame */
  482.     }
  483.  
  484.     theErr = CDSequenceEnd(seqID);                /* Tell the codec we're done with the sequence */
  485.     if (theErr) DebugStr("\pCDSequenceEnd Failed");
  486.  
  487.     theErr = EndMediaEdits( gMedia );                /* We're done adding samples */
  488.     if (theErr) DebugStr("\pEndMediaEdits Failed");
  489.  
  490. /**** changed from 
  491.     theErr = InsertTrackMedia(gTrack,0L,GetMediaDuration(gMedia),0L,GetMediaDuration(gMedia)); */
  492.     theErr = InsertMediaIntoTrack(gTrack,0L,0L,GetMediaDuration(gMedia), 0x00010000);
  493.     if (theErr) DebugStr("\pInsertTrackMedia Failed");
  494.     
  495.     DisposHandle((Handle)pictureBuffer); /* dispose this handle to free its memory */
  496.  
  497.     /* At this point we have the video data accumulated, now we jump to the
  498.        audio handling routine to see if the user wants to add sound to the movie.
  499.     */
  500.     
  501.     AddSoundTrack( gMovie, mdrh); /* this thing return OSErr but I don't care */
  502.  
  503.     /******************************
  504.     *
  505.     * Now close up the movie
  506.     * and throw out our buffers and stuff 
  507.     *
  508.     *******************************/
  509.     resId = 1;
  510.     theErr = AddMovieResource( gMovie, resRefNum, &resId, (char *)sfr.fName );
  511.     if (theErr) DebugStr("\pAddMovieResource Failed");
  512.     
  513.     theErr = CloseMovieFile( resRefNum );
  514.     if (theErr) DebugStr("\CloseMovieFile Failed");
  515.     
  516.     DisposHandle( (Handle) mdrh);
  517.     DisposHandle(compressedFrameBitsH);
  518.     DisposHandle((Handle) imageDescriptorH);
  519.     DisposeGWorld(myGWorld);
  520.     
  521. }
  522.  
  523.  
  524. /******************************
  525. *
  526. * The main routine
  527. *     It doesn't look like much but I'm proud of it 
  528. *
  529. *******************************/
  530. void main()
  531. {
  532.     InitToolbox();            /* Start up the tools */
  533.     ConstructMovie();        /* Make the movie */
  534.     
  535. }
  536.  
  537.